package com.crl.rcdp.gateway.filter;

import com.crl.rcdp.gateway.util.IPUtil;
import com.crl.rcdp.sys.model.SysLog;
import com.crl.rcdp.sys.service.SysLogService;
import io.netty.buffer.ByteBufAllocator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.NettyDataBufferFactory;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.nio.charset.StandardCharsets;

/**
 * @description:
 * @author: 孔垂云
 * @version: 1.0
 * @date: 2020/7/13 0:20
 */
public class LogFilter implements GlobalFilter, Ordered {
    @Autowired
    private SysLogService sysLogService;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        if (HttpMethod.POST.equals(exchange.getRequest().getMethod()) && null != exchange.getRequest().getHeaders().getContentType()
                && exchange.getRequest().getHeaders().getContentType().includes(MediaType.APPLICATION_JSON)
                && !exchange.getRequest().getHeaders().getContentType().includes(MediaType.MULTIPART_FORM_DATA)) {

            return DataBufferUtils.join(exchange.getRequest().getBody()).map(dataBuffer -> {
                byte[] bytes = new byte[dataBuffer.readableByteCount()];
                dataBuffer.read(bytes);
                DataBufferUtils.release(dataBuffer);
                return bytes;
            }).flatMap(bodyBytes -> {
                String msg = new String(bodyBytes, StandardCharsets.UTF_8);
                System.out.println("requestBody: \n {}" + msg);
                this.addLog(exchange, msg);//数据库新增日志
                return chain.filter(exchange.mutate().request(generateNewRequest(exchange.getRequest(), bodyBytes)).build());
            });
        }
        return chain.filter(exchange);
    }

    private ServerHttpRequest generateNewRequest(ServerHttpRequest request, byte[] bytes) {
        URI ex = UriComponentsBuilder.fromUri(request.getURI()).build(true).toUri();
        ServerHttpRequest newRequest = request.mutate().uri(ex).build();
        DataBuffer dataBuffer = stringBuffer(bytes);
        Flux<DataBuffer> flux = Flux.just(dataBuffer);
        newRequest = new ServerHttpRequestDecorator(newRequest) {
            @Override
            public Flux<DataBuffer> getBody() {
                return flux;
            }
        };
        return newRequest;
    }

    private DataBuffer stringBuffer(byte[] bytes) {
        NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT);
        return nettyDataBufferFactory.wrap(bytes);
    }


    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }

    /**
     * 往数据库增加请求日志，后续可以改为写文本日志或记录到ELK
     */
    private void addLog(ServerWebExchange exchange, String body) {
        System.out.println("记录日志"); //TODO
        ServerHttpRequest servletRequest = exchange.getRequest();
        //判断是否需要校验权限
        String servletPath = servletRequest.getPath().toString();//获取请求url
        String authorization = servletRequest.getHeaders().getFirst("Authorization");//获取authorization
        String accessToken = servletRequest.getHeaders().getFirst("accessToken");//accessToken
        String appid = servletRequest.getHeaders().getFirst("appid");//appid
        SysLog sysLog = new SysLog();
        sysLog.setClientIp(IPUtil.getIpAddress(exchange.getRequest()));//ip地址
        sysLog.setAuthType(FilterUtil.getAuthType(authorization, accessToken, appid));//授权方式
        sysLog.setPath(servletPath);//请求地址
        //servicename
        System.out.println(exchange.getAttributes().toString());
        sysLog.setServiceName(exchange.getAttribute("SERVICE_NAME"));
        sysLog.setRequestParam(body);//请求参数
        sysLog.setOwner(FilterUtil.getOwner(authorization, accessToken, appid));//owner
        sysLogService.add(sysLog);
    }
}
